{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 第4章 NumPy基础：数组和矢量计算\n",
    "# https://www.jianshu.com/p/a380222a3292\n",
    "\n",
    "# NumPy(Numerical Python)是Python数值计算最重要的基础包。\n",
    "# 大多数提供科学计算的包都是用 NumPy 的数组作为构建基础。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 考察一个包含一百万整数的数组，和一个等价的Python列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_arr = np.arange(1000000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list = list(range(1000000))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 21 ms\n"
     ]
    }
   ],
   "source": [
    "# 各个序列分别乘以`2`\n",
    "%time for _ in range(10): my_arr2 = my_arr * 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 745 ms\n"
     ]
    }
   ],
   "source": [
    "%time for _ in range(10): my_list2 = [x * 2 for x in my_list]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.1  NumPy的ndarray ：一种多维数组对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.27585062, -0.81248443, -1.19224226],\n",
       "       [-1.54101489, -0.04295139, -0.1923532 ]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "# Generate some random data\n",
    "data = np.random.randn(2, 3)\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ -2.75850622,  -8.12484433, -11.92242263],\n",
       "       [-15.41014891,  -0.42951387,  -1.92353204]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 然后进行数学运算\n",
    "data * 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.55170124, -1.62496887, -2.38448453],\n",
       "       [-3.08202978, -0.08590277, -0.38470641]])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data + data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 3)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建 ndarray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "data1 = [6, 7.5, 8, 0, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr1 = np.array(data1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([6. , 7.5, 8. , 0. , 1. ])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 嵌套序列将会被转换为一个多维数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr2 = np.array(data2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3, 4],\n",
       "       [5, 6, 7, 8]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2.ndim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 4)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('int32')"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.ones(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., 0., 0., 0.],\n",
       "       [0., 0., 0., 0., 0., 0.],\n",
       "       [0., 0., 0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros((3, 6))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[0., 0.],\n",
       "        [0., 0.],\n",
       "        [0., 0.]],\n",
       "\n",
       "       [[0., 0.],\n",
       "        [0., 0.],\n",
       "        [0., 0.]]])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros((2, 3, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.empty(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# `arange`是Python内置函数`range`的数组版"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(15)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "# `ndarray`的数据类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr1 = np.array([1, 2, 3], dtype=np.float64)\n",
    "arr2 = np.array([1, 2, 3], dtype=np.int32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(dtype('float64'), dtype('int32'))"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr1.dtype, arr2.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('int32')"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([1, 2, 3, 4, 5])\n",
    "arr.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "float_arr = arr.astype(np.float64)\n",
    "float_arr.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3.7, -1.2, -2.6,  0.5, 12.9, 10.1])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 浮点数转换成整数，小数部分将会被截取删除\n",
    "arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3, -1, -2,  0, 12, 10])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.astype(np.int32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果字符串表示的全是数字，也可以用`astype`将其转换成数值形式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('S4')"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)\n",
    "numeric_strings.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.25, -9.6 , 42.  ])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numeric_strings.astype(float)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('S4')"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numeric_strings.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ss = numeric_strings.astype(float)\n",
    "ss.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "# NumPy 数组的运算\n",
    "# 矢量化（vectorization）\n",
    "# 大小相等的数组之间的任何算术运算都会将运算应用到元素级"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 2., 3.],\n",
       "       [4., 5., 6.]])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([[1., 2., 3.], [4., 5., 6.]])\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.,  4.,  9.],\n",
       "       [16., 25., 36.]])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr * arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0.],\n",
       "       [0., 0., 0.]])"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr - arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数组与标量的算术运算会将标量值传播到各个元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.        , 0.5       , 0.33333333],\n",
       "       [0.25      , 0.2       , 0.16666667]])"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1 / arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.        , 1.41421356, 1.73205081],\n",
       "       [2.        , 2.23606798, 2.44948974]])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr ** 0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2., 3., 4., 5., 6.])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ss = np.array([4, 9, 16, 25, 36])\n",
    "ss ** 0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.,  4.,  1.],\n",
       "       [ 7.,  2., 12.]])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])\n",
    "arr2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[False,  True, False],\n",
       "       [ True, False,  True]])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2 > arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基本的索引和切片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(10)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5, 6, 7])"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[5:8]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4, 12, 12, 12,  8,  9])"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[5:8] = 12\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([12, 12, 12])"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_slice = arr[5:8]\n",
    "arr_slice"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4, 12, 55, 12,  8,  9])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 修改 `arr_slice` 变动会体现在原始数组 `arr` 中\n",
    "arr_slice[1] = 55\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4, 64, 64, 64,  8,  9])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_slice[:] = 64\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([64, 64, 64])"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 要得到副本，就必须明确地进行复制操作\n",
    "arr_slice_copy = arr[5:8].copy()\n",
    "arr_slice_copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4, 64, 64, 64,  8,  9])"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_slice_copy[1] = 55\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([64, 55, 64])"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_slice_copy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7, 8, 9])"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
    "arr2d[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 3)"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 下面两种方式是等价的\n",
    "arr2d[0][2], arr2d[0, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 1,  2,  3],\n",
       "        [ 4,  5,  6]],\n",
       "\n",
       "       [[ 7,  8,  9],\n",
       "        [10, 11, 12]]])"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])\n",
    "arr3d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr3d[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[42, 42, 42],\n",
       "        [42, 42, 42]],\n",
       "\n",
       "       [[ 7,  8,  9],\n",
       "        [10, 11, 12]]])"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "old_values = arr3d[0].copy()\n",
    "arr3d[0] = 42\n",
    "arr3d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 1,  2,  3],\n",
       "        [ 4,  5,  6]],\n",
       "\n",
       "       [[ 7,  8,  9],\n",
       "        [10, 11, 12]]])"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr3d[0] = old_values\n",
    "arr3d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7, 8, 9])"
      ]
     },
     "execution_count": 76,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr3d[1, 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 切片索引"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4, 64, 64, 64,  8,  9])"
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1,  2,  3,  4, 64])"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[1:6]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6],\n",
       "       [7, 8, 9]])"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2d[:2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[2, 3],\n",
       "       [5, 6]])"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr2d[:2, 1:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 0, 0],\n",
       "       [4, 0, 0],\n",
       "       [7, 8, 9]])"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对切片表达式的赋值操作也会被扩散到整个选区\n",
    "arr2d[:2, 1:] = 0\n",
    "arr2d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 布尔型索引"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [],
   "source": [
    "names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])\n",
    "data = np.random.randn(7, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.72025866,  0.28746103, -0.36930172,  0.89059853],\n",
       "       [-1.21129713,  0.18951414, -0.88106972,  0.77757009],\n",
       "       [-1.23414174,  0.52804509,  0.00579007, -0.63116439],\n",
       "       [-1.65653572,  1.87548736,  1.18103865,  1.35671145],\n",
       "       [ 0.43302858,  0.37995694,  0.41995651,  0.26728924],\n",
       "       [ 0.28784447,  0.6784511 , -0.52050219,  1.70652661],\n",
       "       [ 1.15670565, -1.25424358,  1.08457043,  0.774524  ]])"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True, False, False,  True, False, False, False])"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names == 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.72025866,  0.28746103, -0.36930172,  0.89059853],\n",
       "       [-1.65653572,  1.87548736,  1.18103865,  1.35671145]])"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 这个布尔型数组可用于数组索引：\n",
    "data[names == 'Bob']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.36930172,  0.89059853],\n",
       "       [ 1.18103865,  1.35671145]])"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[names == 'Bob', 2:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.89059853, 1.35671145])"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[names == 'Bob', 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [],
   "source": [
    "# `!=` , `~`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False,  True,  True, False,  True,  True,  True])"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names != 'Bob'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.21129713,  0.18951414, -0.88106972,  0.77757009],\n",
       "       [-1.23414174,  0.52804509,  0.00579007, -0.63116439],\n",
       "       [ 0.43302858,  0.37995694,  0.41995651,  0.26728924],\n",
       "       [ 0.28784447,  0.6784511 , -0.52050219,  1.70652661],\n",
       "       [ 1.15670565, -1.25424358,  1.08457043,  0.774524  ]])"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[~(names == 'Bob')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.21129713,  0.18951414, -0.88106972,  0.77757009],\n",
       "       [-1.23414174,  0.52804509,  0.00579007, -0.63116439],\n",
       "       [ 0.43302858,  0.37995694,  0.41995651,  0.26728924],\n",
       "       [ 0.28784447,  0.6784511 , -0.52050219,  1.70652661],\n",
       "       [ 1.15670565, -1.25424358,  1.08457043,  0.774524  ]])"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cond = names == 'Bob'\n",
    "data[~cond]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')"
      ]
     },
     "execution_count": 96,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True, False,  True,  True,  True, False, False])"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask = (names == 'Bob') | (names == 'Will')\n",
    "mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.72025866,  0.28746103, -0.36930172,  0.89059853],\n",
       "       [-1.23414174,  0.52804509,  0.00579007, -0.63116439],\n",
       "       [-1.65653572,  1.87548736,  1.18103865,  1.35671145],\n",
       "       [ 0.43302858,  0.37995694,  0.41995651,  0.26728924]])"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[mask]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 注意：Python关键字`and`和`or`在布尔型数组中无效。要使用`&`与`|`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.        , 0.28746103, 0.        , 0.89059853],\n",
       "       [0.        , 0.18951414, 0.        , 0.77757009],\n",
       "       [0.        , 0.52804509, 0.00579007, 0.        ],\n",
       "       [0.        , 1.87548736, 1.18103865, 1.35671145],\n",
       "       [0.43302858, 0.37995694, 0.41995651, 0.26728924],\n",
       "       [0.28784447, 0.6784511 , 0.        , 1.70652661],\n",
       "       [1.15670565, 0.        , 1.08457043, 0.774524  ]])"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 通过布尔型数组设置值是一种经常用到的手段。\n",
    "# 为了将data中的所有负值都设置为0，我们只需:\n",
    "data[data < 0] = 0\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7.        , 7.        , 7.        , 7.        ],\n",
       "       [0.        , 0.18951414, 0.        , 0.77757009],\n",
       "       [7.        , 7.        , 7.        , 7.        ],\n",
       "       [7.        , 7.        , 7.        , 7.        ],\n",
       "       [7.        , 7.        , 7.        , 7.        ],\n",
       "       [0.28784447, 0.6784511 , 0.        , 1.70652661],\n",
       "       [1.15670565, 0.        , 1.08457043, 0.774524  ]])"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 通过一维布尔数组设置整行或列的值也很简单：\n",
    "data[names != 'Joe'] = 7\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 花式索引\n",
    "# 花式索引（Fancy indexing）是一个NumPy术语，它指的是利用整数数组进行索引。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., 0.],\n",
       "       [1., 1., 1., 1.],\n",
       "       [2., 2., 2., 2.],\n",
       "       [3., 3., 3., 3.],\n",
       "       [4., 4., 4., 4.],\n",
       "       [5., 5., 5., 5.],\n",
       "       [6., 6., 6., 6.],\n",
       "       [7., 7., 7., 7.]])"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.empty((8, 4))\n",
    "for i in range(8):\n",
    "    arr[i] = i\n",
    "\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4., 4., 4., 4.],\n",
       "       [3., 3., 3., 3.],\n",
       "       [0., 0., 0., 0.],\n",
       "       [6., 6., 6., 6.]])"
      ]
     },
     "execution_count": 104,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 为了以特定顺序选取行子集，只需传入一个用于指定顺序的整数列表或ndarray即可：\n",
    "arr[[4, 3, 0, 6]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5., 5., 5., 5.],\n",
       "       [3., 3., 3., 3.],\n",
       "       [1., 1., 1., 1.]])"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 使用负数索引将会从末尾开始选取行：\n",
    "arr[[-3, -5, -7]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3],\n",
       "       [ 4,  5,  6,  7],\n",
       "       [ 8,  9, 10, 11],\n",
       "       [12, 13, 14, 15],\n",
       "       [16, 17, 18, 19],\n",
       "       [20, 21, 22, 23],\n",
       "       [24, 25, 26, 27],\n",
       "       [28, 29, 30, 31]])"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(32).reshape((8, 4))\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 4, 23, 29, 10])"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[[1, 5, 7, 2], [0, 3, 1, 2]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 4,  7,  5,  6],\n",
       "       [20, 23, 21, 22],\n",
       "       [28, 31, 29, 30],\n",
       "       [ 8, 11,  9, 10]])"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 记住，花式索引跟切片不一样，它总是将数据复制到新数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数组转置和轴对换\n",
    "# 转置是重塑的一种特殊形式，它返回的是源数据的视图（不会进行任何复制操作）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8,  9],\n",
       "       [10, 11, 12, 13, 14]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "arr = np.arange(15).reshape((3,5))\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  5, 10],\n",
       "       [ 1,  6, 11],\n",
       "       [ 2,  7, 12],\n",
       "       [ 3,  8, 13],\n",
       "       [ 4,  9, 14]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.07871902, -1.18259835,  1.01632919],\n",
       "       [-0.39361144, -0.40463226,  0.02028667],\n",
       "       [-0.00704537, -0.19971173, -0.54463584],\n",
       "       [-0.82113202, -1.44031678, -1.74485171],\n",
       "       [ 2.00605371,  0.48570307,  0.55786674],\n",
       "       [ 1.26041615, -1.68101615,  0.63254478]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在进行矩阵计算时，经常需要用到该操作，比如利用np.dot计算矩阵内积：\n",
    "arr = np.random.randn(6, 3)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7.60577246, 1.47462302, 2.24865238],\n",
       "       [1.47462302, 6.73838609, 0.61943109],\n",
       "       [2.24865238, 0.61943109, 5.08580045]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(arr.T, arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7]],\n",
       "\n",
       "       [[ 8,  9, 10, 11],\n",
       "        [12, 13, 14, 15]]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对于高维数组，transpose需要得到一个由轴编号组成的元组才能对这些轴进行转置\n",
    "arr = np.arange(16).reshape((2, 2, 4))\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 8,  9, 10, 11]],\n",
       "\n",
       "       [[ 4,  5,  6,  7],\n",
       "        [12, 13, 14, 15]]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.transpose((1, 0, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7]],\n",
       "\n",
       "       [[ 8,  9, 10, 11],\n",
       "        [12, 13, 14, 15]]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  4],\n",
       "        [ 1,  5],\n",
       "        [ 2,  6],\n",
       "        [ 3,  7]],\n",
       "\n",
       "       [[ 8, 12],\n",
       "        [ 9, 13],\n",
       "        [10, 14],\n",
       "        [11, 15]]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.swapaxes(1, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.2 通用函数：快速的元素级数组函数\n",
    "# 通用函数（即ufunc）是一种对ndarray中的数据执行元素级运算的函数。\n",
    "# 你可以将其看做简单函数（接受一个或多个标量值，并产生一个或多个标量值）的矢量化包装器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(10)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,\n",
       "       2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,\n",
       "       5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,\n",
       "       2.98095799e+03, 8.10308393e+03])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.exp(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这些都是一元（unary）ufunc。\n",
    "# 另外一些（如add或maximum）接受2个数组（因此也叫二元（binary）ufunc），\n",
    "# 并返回一个结果数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.random.randn(8)\n",
    "y = np.random.randn(8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.78865859, -0.56031175, -0.39431729, -0.50158122, -0.72067517,\n",
       "       -0.59419733,  0.21671386, -0.01174963])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.37919745,  0.86769513, -0.95109161,  0.53834697, -1.52211442,\n",
       "        1.01399932, -0.45995167,  1.80588613])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.37919745,  0.86769513, -0.39431729,  0.53834697, -0.72067517,\n",
       "        1.01399932,  0.21671386,  1.80588613])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.maximum(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 有些ufunc的确可以返回多个数组。modf就是一个例子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6.02513843, -8.06173941,  2.1090912 ,  0.6682545 ,  1.08380453,\n",
       "        1.86020637,  2.38659442])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.random.randn(7) * 5\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "remainder, whole_part = np.modf(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.02513843, -0.06173941,  0.1090912 ,  0.6682545 ,  0.08380453,\n",
       "        0.86020637,  0.38659442])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "remainder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6., -8.,  2.,  0.,  1.,  1.,  2.])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "whole_part"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Ufuncs可以接受一个out可选参数，这样就能在数组原地进行操作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6.02513843, -8.06173941,  2.1090912 ,  0.6682545 ,  1.08380453,\n",
       "        1.86020637,  2.38659442])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "e:\\python_env\\py3\\lib\\site-packages\\ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in sqrt\n",
      "  \"\"\"Entry point for launching an IPython kernel.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([2.45461574,        nan, 1.45227105, 0.81746835, 1.04105933,\n",
       "       1.36389383, 1.54486065])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "e:\\python_env\\py3\\lib\\site-packages\\ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in sqrt\n",
      "  \"\"\"Entry point for launching an IPython kernel.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([2.45461574,        nan, 1.45227105, 0.81746835, 1.04105933,\n",
       "       1.36389383, 1.54486065])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(arr, arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2.45461574,        nan, 1.45227105, 0.81746835, 1.04105933,\n",
       "       1.36389383, 1.54486065])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 可用的一元ufunc和二元ufunc，参考 https://www.jianshu.com/p/a380222a3292"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.3 利用数组进行数据处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 假设我们想要在一组值（网格型）上计算函数sqrt(x^2+y^2)。\n",
    "# np.meshgrid函数接受两个一维数组，并产生两个二维矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],\n",
       "       [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],\n",
       "       [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],\n",
       "       ...,\n",
       "       [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],\n",
       "       [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],\n",
       "       [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "points = np.arange(-5, 5, 0.01) # 1000 equally spaced points\n",
    "xs, ys = np.meshgrid(points, points)\n",
    "ys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 现在，对该函数的求值运算就好办了，\n",
    "# 把这两个数组当做两个浮点数那样编写表达式即可："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,\n",
       "        7.06400028],\n",
       "       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,\n",
       "        7.05692568],\n",
       "       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,\n",
       "        7.04985815],\n",
       "       ...,\n",
       "       [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,\n",
       "        7.04279774],\n",
       "       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,\n",
       "        7.04985815],\n",
       "       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,\n",
       "        7.05692568]])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = np.sqrt(xs ** 2 + ys ** 2)\n",
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 作为第9章的先导，我用matplotlib创建了这个二维数组的可视化："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.colorbar.Colorbar at 0x1b049278>"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Image plot of $\\\\sqrt{x^2 + y^2}$ for a grid of values')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.title(\"Image plot of $\\sqrt{x^2 + y^2}$ for a grid of values\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.colorbar.Colorbar at 0x1b1fa898>"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将条件逻辑表述为数组运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "# numpy.where函数是三元表达式x if condition else y的矢量化版本。\n",
    "xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])\n",
    "yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])\n",
    "cond = np.array([True, False, True, True, False])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1.1, 2.2, 1.3, 1.4, 2.5]"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 假设我们想要根据cond中的值选取xarr和yarr的值：\n",
    "# 当cond中的值为True时，选取xarr的值，否则从yarr中选取。\n",
    "#列表推导式的写法应该如下所示：\n",
    "\n",
    "result = [(x if c else y)\n",
    "         for x, y, c in zip(xarr, yarr, cond)]\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.1, 2.2, 1.3, 1.4, 2.5])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 若使用np.where，则可以将该功能写得非常简洁\n",
    "result = np.where(cond, xarr, yarr)\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.2653941 ,  1.34355526, -0.79752448,  0.35508248],\n",
       "       [-0.07433877,  0.08434191,  1.25308699,  0.05096698],\n",
       "       [-1.49334935, -1.29580391,  1.30955639,  0.10466173],\n",
       "       [-0.55279268,  1.67359694, -0.02076183, -1.02291919]])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 假设有一个由随机数据组成的矩阵，你希望将所有正值替换为2，将所有负值替换为－2。\n",
    "# 若利用np.where，则会非常简单：\n",
    "arr = np.random.randn(4, 4)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ True,  True, False,  True],\n",
       "       [False,  True,  True,  True],\n",
       "       [False, False,  True,  True],\n",
       "       [False,  True, False, False]])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 2,  2, -2,  2],\n",
       "       [-2,  2,  2,  2],\n",
       "       [-2, -2,  2,  2],\n",
       "       [-2,  2, -2, -2]])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.where(arr > 0, 2, -2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 2.        ,  2.        , -0.79752448,  2.        ],\n",
       "       [-0.07433877,  2.        ,  2.        ,  2.        ],\n",
       "       [-1.49334935, -1.29580391,  2.        ,  2.        ],\n",
       "       [-0.55279268,  2.        , -0.02076183, -1.02291919]])"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 我可用常数2替换arr中所有正的值：\n",
    "np.where(arr > 0, 2, arr) # set only positive values to 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数学和统计方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.29818577,  0.22204759, -0.27715809,  2.09689135],\n",
       "       [-0.55450431,  0.39881936, -0.39176307,  0.47165829],\n",
       "       [ 0.53035191, -0.33463427,  1.00632742, -1.11734232],\n",
       "       [ 0.80425443,  1.27566968, -1.52139967, -3.93445276],\n",
       "       [ 0.56429097, -1.13918408, -0.01865137,  0.01694589]])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.random.randn(5, 4)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.08018236482792739"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.08018236482792739"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.mean(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1.6036472965585478"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.58499165, -0.01894743,  0.02117568, -0.84398208, -0.14414965])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# mean和sum这类的函数可以接受一个axis选项参数，用于计算该轴向上的统计值\n",
    "arr.mean(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.64257876,  0.42271827, -1.20264478, -2.46629955])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.sum(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  3,  6, 10, 15, 21, 28], dtype=int32)"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 这里，arr.mean(1)是“计算行的平均值”，arr.sum(0)是“计算每列的和”。\n",
    "# 其他如cumsum和cumprod之类的方法则不聚合，而是产生一个由中间结果组成的数组：\n",
    "arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])\n",
    "arr.cumsum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2],\n",
       "       [3, 4, 5],\n",
       "       [6, 7, 8]])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在多维数组中，累加函数（如cumsum）返回的是同样大小的数组，\n",
    "# 但是会根据每个低维的切片沿着标记轴计算部分聚类：\n",
    "arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [ 3,  5,  7],\n",
       "       [ 9, 12, 15]], dtype=int32)"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.cumsum(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  0,   0,   0],\n",
       "       [  3,  12,  60],\n",
       "       [  6,  42, 336]], dtype=int32)"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.cumprod(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 表4-5： 基本数组统计方法\n",
    "# 参考： https://www.jianshu.com/p/a380222a3292"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用于布尔型数组的方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "44"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在上面这些方法中，布尔值会被强制转换为1（True）和0（False）。\n",
    "# 因此，sum经常被用来对布尔型数组中的True值计数：\n",
    "\n",
    "arr = np.random.randn(100)\n",
    "(arr > 0).sum() # Number of positive values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 另外还有两个方法any和all，它们对布尔型数组非常有用。\n",
    "# any用于测试数组中是否存在一个或多个True，\n",
    "# 而all则检查数组中所有值是否都是True：\n",
    "bools = np.array([False, False, True, False])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bools.any()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bools.all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 排序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.29403092, -1.33564449,  0.20276366,  0.28638612, -0.31866204,\n",
       "        0.02065594])"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 跟Python内置的列表类型一样，NumPy数组也可以通过sort方法就地排序：\n",
    "arr = np.random.randn(6)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.33564449, -0.31866204, -0.29403092,  0.02065594,  0.20276366,\n",
       "        0.28638612])"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.sort()\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.7170422 , -1.49569125, -1.042223  ],\n",
       "       [ 0.08237545, -1.35865049,  0.44559205],\n",
       "       [-0.39869262, -1.44250496,  0.15951801],\n",
       "       [-0.45737778,  0.02075898,  0.94028667],\n",
       "       [-0.6900289 ,  2.17732497, -2.05299644]])"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 多维数组可以在任何一个轴向上进行排序，只需将轴编号传给sort即可：\n",
    "arr = np.random.randn(5, 3)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.49569125, -1.042223  , -0.7170422 ],\n",
       "       [-1.35865049,  0.08237545,  0.44559205],\n",
       "       [-1.44250496, -0.39869262,  0.15951801],\n",
       "       [-0.45737778,  0.02075898,  0.94028667],\n",
       "       [-2.05299644, -0.6900289 ,  2.17732497]])"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.sort(1)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1.5738766751498692"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 顶级方法np.sort返回的是数组的已排序副本，而就地排序则会修改数组本身。\n",
    "# 计算数组分位数最简单的办法是对其进行排序，然后选取特定位置的值：\n",
    "large_arr = np.random.randn(1000)\n",
    "large_arr.sort()\n",
    "large_arr[int(0.05 * len(large_arr))] # 5% quantile"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['Bob', 'Joe', 'Will'], dtype='<U4')"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 唯一化以及其它的集合逻辑\n",
    "# NumPy提供了一些针对一维ndarray的基本集合运算。\n",
    "# 最常用的可能要数np.unique了，它用于找出数组中的唯一值并返回已排序的结果：\n",
    "\n",
    "names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])\n",
    "np.unique(names)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4])"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])\n",
    "np.unique(ints)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Bob', 'Joe', 'Will']"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 拿跟np.unique等价的纯Python代码来对比一下：\n",
    "sorted(set(names))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True, False, False,  True,  True, False,  True])"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 另一个函数np.in1d用于测试一个数组中的值在另一个数组中的成员资格，返回一个布尔型数组：\n",
    "values = np.array([6, 0, 0, 3, 2, 5, 6])\n",
    "np.in1d(values, [2, 3, 6])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 表4-6： 数组的集合运算\n",
    "# 参考：https://www.jianshu.com/p/a380222a3292"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.4 用于数组的文件输入输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr = np.arange(10)\n",
    "np.save('some_array', arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果文件路径末尾没有扩展名.npy，则该扩展名会被自动加上。\n",
    "# 然后就可以通过np.load读取磁盘上的数组：\n",
    "np.load('some_array.npy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过np.savez可以将多个数组保存到一个未压缩文件中，将数组以关键字参数的形式传入即可：\n",
    "np.savez('array_archive.npz', a=arr, b=arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 加载.npz文件时，你会得到一个类似字典的对象，该对象会对各个数组进行延迟加载：\n",
    "arch = np.load('array_archive.npz')\n",
    "arch['b']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果要将数据压缩，可以使用numpy.savez_compressed\n",
    "np.savez_compressed('arrays_compressed.npz', a=arr, b=arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.5 线性代数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([[1., 2., 3.], [4., 5., 6.]])\n",
    "y = np.array([[6., 23.], [-1, 7], [8, 9]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 2., 3.],\n",
       "       [4., 5., 6.]])"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 6., 23.],\n",
       "       [-1.,  7.],\n",
       "       [ 8.,  9.]])"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 28.,  64.],\n",
       "       [ 67., 181.]])"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.dot(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 28.,  64.],\n",
       "       [ 67., 181.]])"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# x.dot(y)等价于np.dot(x, y)：\n",
    "np.dot(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6., 15.])"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 一个二维数组跟一个大小合适的一维数组的矩阵点积运算之后将会得到一个一维数组\n",
    "np.dot(x, np.ones(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6., 15.])"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# @符（类似Python 3.5）也可以用作中缀运算符，进行矩阵乘法：\n",
    "x @ np.ones(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  5.96162832,   8.3410158 , -11.19235581,  -1.25627504,\n",
       "         -8.67418699],\n",
       "       [  8.3410158 ,  12.30262652, -16.77009999,  -1.82626943,\n",
       "        -12.23812344],\n",
       "       [-11.19235581, -16.77009999,  23.96059517,   2.85764268,\n",
       "         16.47523972],\n",
       "       [ -1.25627504,  -1.82626943,   2.85764268,   0.57965412,\n",
       "          1.92386133],\n",
       "       [ -8.67418699, -12.23812344,  16.47523972,   1.92386133,\n",
       "         13.04936365]])"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from numpy.linalg import inv, qr\n",
    "X = np.random.randn(5, 5)\n",
    "mat = X.T.dot(X)\n",
    "inv(mat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.00000000e+00,  3.81960746e-15,  1.64770915e-14,\n",
       "         1.94619744e-15, -8.13188621e-15],\n",
       "       [-6.23294572e-16,  1.00000000e+00, -4.01870350e-15,\n",
       "        -5.11567933e-16,  1.76117936e-14],\n",
       "       [-2.59295602e-15, -3.72830693e-15,  1.00000000e+00,\n",
       "         2.01225560e-16,  7.85287980e-15],\n",
       "       [-5.73622524e-15, -1.65026141e-15,  1.22383241e-14,\n",
       "         1.00000000e+00, -3.03320802e-15],\n",
       "       [ 3.94196163e-15,  1.08484990e-14, -1.00204855e-14,\n",
       "        -3.64196798e-16,  1.00000000e+00]])"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mat.dot(inv(mat))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-8.459283  ,  5.00913195,  1.82183045, -1.54700737, -3.02412885],\n",
       "       [ 0.        , -7.78172415, -4.21491396,  7.36214858, -3.0901086 ],\n",
       "       [ 0.        ,  0.        , -0.73516884,  2.75044776,  0.56905009],\n",
       "       [ 0.        ,  0.        ,  0.        , -2.33232931,  0.37066288],\n",
       "       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.03862087]])"
      ]
     },
     "execution_count": 96,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q, r = qr(mat)\n",
    "r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.6 伪随机数生成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.3821995 ,  0.32753222,  0.57553738, -1.50226718],\n",
       "       [ 1.225112  ,  0.73604708, -0.09140696, -1.86222721],\n",
       "       [-0.08339836, -0.25807203,  0.0251763 , -0.58775566],\n",
       "       [ 0.47914397,  0.12284613, -1.33608126, -1.31268776]])"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以用normal来得到一个标准正态分布的4×4样本数组：\n",
    "samples = np.random.normal(size=(4, 4))\n",
    "samples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "642 ms ± 811 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "from random import normalvariate\n",
    "N = 1000000\n",
    "%timeit samples = [normalvariate(0, 1) for _ in range(N)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25.7 ms ± 59.6 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit np.random.normal(size=N)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.47143516, -1.19097569,  1.43270697, -0.3126519 , -0.72058873,\n",
       "        0.88716294,  0.85958841, -0.6365235 ,  0.01569637, -2.24268495])"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 你可以用NumPy的np.random.seed更改随机数生成种子：\n",
    "np.random.seed(1234)\n",
    "rng = np.random.RandomState(1234)\n",
    "rng.randn(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4.7 示例：随机漫步"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x1c1d6208>]"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYAAAAD8CAYAAAB+UHOxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzt3Xl4I/d5J/jvi4P3jWIfvJokijpaavUhNrubgDx2ZHstj21tEk8iZSbxPPGu1hnnSZzJ7sazM5Nnd57HM5vEcWZi+7GjxJN1ZrO2J5YPTSLLlzyWAPYh9t3qQyyS3U02u9ks8L4J4N0/gAIBECBBAmDheD/Pw6eBQhH1A6tRb9Wv3t/7I2aGEEKI4mMxuwFCCCHMIQFACCGKlAQAIYQoUhIAhBCiSEkAEEKIIiUBQAghipQEACGEKFISAIQQokhJABBCiCJlM7sBm1EUhdvb281uhhBC5I3z58/rzNyYyro5HQDa29vR399vdjOEECJvENGdVNeVLiAhhChSEgCEEKJISQAQQogiJQFACCGKlAQAIYQoUhIAhBCiSEkAEEKIIiUBQKTt0sg0+m9Pblg+rC/gpzfGTWiRECIVEgBE2j77yhV85luXNiz/49dv4lP/73ksrvpNaJUQYisSAERaJuZWcPPBHEanlnDXtxhZHggy+gZ9WAswzg1vvDoQQpgv7QBARI8S0aWon1ki+kzcOu8lopmodf4w3e2K3NA3qEcee6MevzM2g5mltfA6vl1vlxBia2nXAmLmWwCOAAARWQHcA/DdBKu+xcwfSXd7Ird4NR215XaU2S3waDpe7GkLLw8d9B/ZWwXPgL7ZWwghTJLpLqBnAQwyc8rFiET+YmZ4NR96nQ64VAV9mo5gkAGEAsNj+6rxscNNuH5/Fr75FZNbK4SIl+kA8AKAbyR57RQRXSaiHxDRExnerjDBHd8i7k0voVdV4FYVTC2u4caDWSyvBXDu9iR6nQpcqgIAOD0k3UBC5JqMBQAiKgHwMQB/l+DlCwAOMPNhAF8E8L1N3uclIuonov6JiYlMNU9kgUcLde241fUDvVfTcf7OFFb9Qbi7HDjUXIvqMhu8mnQDCZFrMnkF8ByAC8y8IfGbmWeZeT78+DUAdiJSEr0JM7/MzN3M3N3YmNKcBsIkXk1Hc1052h0V2FtTBnVPFbyaD15Nh81C6OlwwGa14GSnIxIshBC5I5MB4EUk6f4hon1EROHHPeHtSp9AHgsEGaeHQv3/4V0Lt6rg3PAkfnZrAkda61BVaossH5mMTRMVQpgvIwGAiCoAfADAd6KWfYqIPhV++nEA14joMoA/B/ACM3Mmti3McX1sFtOLa3B3rV/IuVQFS2sB3Lg/G+kSMpYDsWmiQgjzZWRKSGZeBOCIW/bVqMdfAvClTGxL5AajS6fXuX6gP9HZAKuFEAhyTGBwNlZiX01ZTJqoEMJ8MhJYYHHVjxdfPoPzd6ZS/h2vpuPRvdVorC6NLKsps+OpllpUlFhxuKUuspyI0Ks6YtJEhRDmkwAgcGbIh9NDPrxyYTSl9ZfXAnj79iR6VceG1/7gQ4/h3//iIZTYYv9rRaeJCiFyQ0a6gER+8wyE7senmqp54c4UVvxBPNO1MZHrZOfGoAAgJk30iabaHbZUCJFJcgUg4NV0EIUGdo1Mbp2p44lK80yVkSbq0ST5S4hcIQGgyD2cW8at8Tn84pFmALHF3ZLxDvpi0jxT5VYVvD08iRV/YEdtFUJklgSAInc6XKnzE73taKwu3fIMfWZxDVdHp2PSPFNlpIlevDu9o7YKITJLAkCR8wyEqnk+2VwLd1xBt0ROD/kQZOwoAJzobICFUr/XIITILgkARSxUzVPHqU4HrBaCS1XgW1jFrfG5pL/TN6ijosSKI611SddJpqbMjsOtdRIAhMgREgCK2G3fIsZmluEKZ/O4wmmdmx2gPZqOEx0NG9I8U+VWFVwencHs8tqOfl8IkTkSAIqYMZrX5Qwd+PfXlqOzsTJp4bb7M0sYmljYUfePodepIBBknB2SaSKFMJsEgCLWp+loqi1Dh1IZWWYUdFv1Bzesb8zylU4AOHagDmV2i3QDCZEDJAAUiFV/EKNTG3P4mRm39YUNy41J212qEqnmCYQO7ourAVwa2Zip49V0KFUleHRv9Y7bWWqzoqfDIQFAiBwgAaBA/OVbQ3j2T3+O6cXVmOWvX3uA937+v+OdsZmY5cak7fFn8yc7HbAQNnQDRW4YOxVYLIR0uJwODDycx/jsclrvI4RIjwSAAvHfbz3Eij+IM3FTL/7s1kMAwM/fjZ1dzejOia/nU1tux6GWOvTFBQDt4Twezq3AnaD+z3YZQSeVQWdCiOyRAFAA5lf8kcFV0WfuzAzPQOh5fJeLUc1zT3XZhvdzqw5cHJnGXFSmTuSGcRr9/4aD+2tQX2GP1CASQphDAkABODfsgz/IaKgsiZzZA+tpng2VJXj79hSW10IlGDar5gkArnCmzrnh9Uwdr6bjgKMCLfUVabfXYiH0OhV4NR0yL5AQ5pEAUAC8mg+lNgs+6e7AsL6Ae9NL4eWhs/ZPv0/Fqj8YqfdvVPN0JzmbP3agHqU2SySY+ANBnBmazMjZv8GlKngwu4yhBDeohRC7QwJAAfBqOrrb6/Hs43siz41/m2rL8KvHW2GzUKQbx6PpsFoIJ5KUbi6zW9HT0RB5n8ujM5hf8ScNGDvhjioPLYQwhwSAPPdwbhk3H8zBpSp4dG81lKoSeDU9Js2zqtSGo211MYFhq2qevU4Ft8bn8HBuOVIu+lSSgLETbY4KtNSXR+5RCCF2nwSAPGdU83SH8/lDfeu+DWmevU4FV+/N4K5vEVfvzWzZnWOcoZ8e9MGj6XiiqQb1lSUZbbtbVXB6yAd/YOOgMyFE9mUsABDRbSK6SkSXiKg/wetERH9ORBoRXSGiY5nadjHzaqFqnsYsW25VgT6/gr/23gawnubp7lLADPzZT95FkLFld87BphrUVdjxo3fGcfHuVEb7/w0uVcHcsh/XxmSaSCHMkOkrgPcx8xFm7k7w2nMAusI/LwH4Soa3XXSMNE+jmieASGG37126F5PmeaS1DpUlVnzv0j2U27eu5mm1EE51OvDatftYCzBczswHgF7n1sXnhBDZs5tdQM8D+BsOOQOgjoj27+L2C058NU8AaK4rR7ujAsyxg7zsVgt6OhrAHKrLn0o1T5caumoosVpwvL0h4+13VJXi8f01ch9ACJNkMgAwgB8R0XkieinB680ARqKej4aXiR0yzpzju3OM7ppUlydjrPf0gXqUl1jTamvybThw/s4UllZjp4lcXgvgT390CzNLUjZaiGzJZABwMfMxhLp6Pk1E74l7PVEBmQ2jgIjoJSLqJ6L+iYmJBL8iDEaaZ7sjdnDWx59uwalOB07GZe08d2g/ug/U40NP7kvp/Q84KvCPn9qPXzvRlrE2x3OpClYDQfTfiS0P/dMbD/HFNzR8/9K9rG1biGKXsQDAzGPhfx8C+C6AnrhVRgG0Rj1vATCW4H1eZuZuZu5ubGzMVPMKTrJqngBwtK0e33jpJCrj0jyb68rx7d/qTXk0LxHhy792DB893JSxdsfr6WiA3Uobis9FxixI95AQWZORAEBElURUbTwG8EEA1+JWexXAb4SzgU4CmGHm+5nYfjG6PjaLmaU1uLsyf3N2N1WU2HC0rR59cZPRG4XiTg/5ENhkjmIhxM5l6gpgLwAPEV0GcA7APzDz60T0KSL6VHid1wAMAdAA/CWAf5GhbRcl4wy5NwvZObvNrSq4NjaDqYVQKeuRyUXc8S3i6QP1mFv24+q9mS3eQQixExkJAMw8xMyHwz9PMPPnwsu/ysxfDT9mZv40MzuZ+RAzbxgrIFJnVPNsrC41uylpc6kOMIfO9oH1m9v/2//waMxzIURmyUjgPGRU88zG4CwzPNUSKkthXNV4B33YU12KEx0NeHx/jQQAIbJEAkAeilTz7MpcbR4z2a0WnOxsQJ+mIxhk9Gl65Oa2W3Wg//bGNFEhRPokAOQhj6bDZiH0dBRGAABC9zJu+xbx05sP4VtYjVzdJEsTFUKkTwJAHvIO+ras5plvjGymz//wFoDQfQFgPU3Uq8nsYUJkmgSAPDOzuIaro9MF0/9v6NpThcbqUtwan4OzsRL7a8sBrKeJyn0AITJPAkCeOT3kC1XzzPP8/3ih/v71bp9oRpro9OKqGU0TomBJAMgzfYM6KkqsONyyeTXPfORKEgCMNNG+QekGEiKTCqcTuUh4NB0nOlKr5plvPnp4P9YCQTz72J6Y5UaaqFfT8eFDUkBWiEwpvKNIAbs/s4ShiYWC6/83lNqseLGnDTZr7H9LI01U7gMIkVkSAPKIkQlTqAFgM0aa6OjUotlNEaJgSADII15Nh1JVgkf3VpvdlF1n3PSOLxonhNg5CQB5gpnh0XT0OhVYLImmVihsRppofNloIcTOSQDIE9rDeUzMrUQGSBUbIoLL6UDfoA5mKQ8tRCZIAMgTxplvMfb/G1yqAn1+FbfG58xuihAFQQJAnvBqOtodFSnP5lWIjOAns4QJkRkSAPKAPxDEmaFJ9Bbx2T8ANNWVo1OplHRQITJEAkAeuDw6g/kVf6RUQjFzqQrODk9iLRA0uylC5D0JAHnAq+kgAk51FucN4GguVcHiagCXRqbNbooQeU8CQB7waDqeaKpBfWWJ2U0x3alOBywk9wGEyAQJADlucdWPi3enijr7J1pthR2HmmvRNygBQIh0SQDIceeGJ7EWYOn/j+JSFVy8O435Fb/ZTREir6UdAIiolYh+RkQ3iOgdIvrdBOu8l4hmiOhS+OcP091usfBqOkqsFnQfaDC7KTnDpSrwBxnnhqUshBDpyEQ5aD+A32fmC0RUDeA8Ef2Yma/HrfcWM38kA9srKl7Nh6cP1KO8xGp2U3LG0wfqUWqzwKv58AuP7TW7OULkrbSvAJj5PjNfCD+eA3ADQHO67ysA3/wKrt+fLbjZv9JVZrfieLuUhxYiXRm9B0BE7QCOAjib4OVTRHSZiH5ARE9s8h4vEVE/EfVPTExksnl5x5gBq9cp6Z/xelUHbj6Yw8TcitlNESJvZSwAEFEVgFcAfIaZZ+NevgDgADMfBvBFAN9L9j7M/DIzdzNzd2NjY6aal5f6BnVUl9lwqLnW7KbkHOOmuGQDCbFzGQkARGRH6OD/t8z8nfjXmXmWmefDj18DYCci6dfYgkfTcarTsWGGLAE80VSL2nK7dAMJkYZMZAERgK8BuMHMX0iyzr7weiCinvB2JYVjE3d9ixiZXJL8/ySsFsKpTge8mk/KQwuxQ5nIAnIB+HUAV4noUnjZ/wGgDQCY+asAPg7gt4jID2AJwAss39pNeQel/PNWXF0KXn/nAe74FtGuVJrdHCHyTtoBgJk9ADadooqZvwTgS+luK11/7R1GQ2UJnj+SO0lKX/jxuzjWVof3PronZrlH07GvpgzORjmwJWPcB3hL0zcEgL98cwj768rwkaeazGiaEHmhaDqX1wJBfP6Ht/CffjJgdlMifPMr+POfDuDlN4dilgeDjD5NR6/qQLjnTCTQ7qhAU20Z+uLuAyyvBfD5H93Cl97QTGqZEPmhaALAldFpLKwGMKQvYGx6yezmAABOD4Vug/TfmcLyWiCy/MaDWUwtrkn5hy0QEVyqgtNDPgSC6z2KF+5OYcUflDRRIbZQNAHAM7B+zzlXMkeMdqz6g+i/PbVhufT/b83dpWB6cQ3Xx9Yzj6P3r6SJCpFc0QQAr6bjyeYaKFUlORMAPJoOl+qA3UqROX9Dy33o2lOFvTVlJrYuP/Q6w9NExv39jrTWSZqoEFsoigCwsOLHhbtTeKarEb1OBd5B81MHjTTPDx7ch6Nt9ZED1Yo/gLeHJ+XsP0WN1aV4dG915O83s7SGq6PTeM8jjeh1SpqoEJspigBwbngS/iDD5VTgVhVMzK1g4OG8qW2KTvN0ORVcG5vB9OIqLt6dxtJaQALANrhUBW/fnsTyWgBnhnwIcihDqFdVcG96CXd8i2Y3UYicVBQBwKvpKLFZ0N1ej141VFfH7BmlPJqOvTWlcDZWwt3lADNwetAHr6bDaiGc6JTyz6lydzmw4g/iwp0peDUd5XYrjrTWRW6ie6QbSIiEiiIAeDQd3QfqUWa3oqW+Au2OClP7ho00T5eqgIjwVEsdKkus8Gg6vJqOp1pqUVNmN619+aanwwGbhSJ/vxOdDSixWSJponIfQIjECj4ATMyt4OaDuZguFZeq4OzwJNYCQVPaFJ/mabdacLLTgTduPsTl0RlJ/9ymqlIbjrTW4fuXxjA4sRD5+yVLExVChBR8ADDSAKMPqm5VwfyKH1dGp01pU6I0T5eq4P7MMgJBlv7/HXCF+/uNx4ZEaaJCiJCCDwBeTUdNmQ1PRpVUPuV0gCh2bMBu8mg+qHFpnsZBq8xuwdG2OlPalc+Mv5+jsgSP7q2OLD8Vnksh0X2AQJCx6t94FcjMWPEHNiwXotAUdABgZng1H052OmC1rJdUqKsowZNNtab0DUfSPOMmeXlkbxX21pTiRIcDpTaZ/nG7jrTWoarUBpeqwBK1r/dUl8WkiUb7v39wAx/9omdDmug3zo3gxL//qUw6LwpeQQeAO75F3JtewjMJplR0qQoujkxhYZe/5Eaap7srdrIbIsLf/OYJ/IdfOrSr7SkUJTYLvvnSSfybjzy+4bXoNNFor7/zALfG53A7Lk309XceYHpxTSadFwWvoAOAcdnfm6BP3aU6sBZgnLs9uatt8mo6LISEaZ6P7qtGU135rrankDzZXIs91RtHT7vU9TRRgzEQD4jtHlrxByIHfrO6CIXYLQUdAPoGdeyvLUNnglrxx9tDqYLxlSSzzavpONxaJ2meu+hEuAsw+kBvDMSrKLHG/B+4eHcay2vB0HKpIyQKXMEGgECQ0Tfoi+TaxyuzW9F9oB4ebffO8maX1yTN0wRVpTYcba2Dd3B9XxsD8T58aD/6BtfTRI0rtE/0tuPmgzk8nFs2q9lCZF3BBoDrY7OYXlyDS3UkXcelKrhxfxb6/O6UDD47NClpniZxqQqujk5jZnEtZiDeM10KZpbW8M7YDIBQYDjcWofnntwHIDQ6W4hCVbABIFJrx5n8YGsciHfrS+7VdEnzNIlLVRDk0BwM0QPxjDRRr+bD7PIarozOwOVU8ERTLWrKbDKKWBS0wg0Amo5H9lZhzyYllQ8116J6F7/kXk1Hj6R5muJIax0qSqzwhstFAKGgEJ0mGn2FZrUQep0KPAO6VBMVBasgA8DyWgDnhicjteKTCX3JHbtSLGx8dhkDD+fh3qRLSmRPic2CEx0N8A7q8MYNxDPSRN+4+RBldguOHQhdobm6FIzNLG9IExWiUGQkABDRh4joFhFpRPTZBK+XEtG3wq+fJaL2TGw3GWNKwFRutrpUBaNTS7ib5S+5kVGyVVAS2eNSFQxNLOD0oC/m/4aRJvrK+VEcb2+IXKG5It1D0g0kClPaAYCIrAC+DOA5AAcBvEhEB+NW+ySAKWZWAfwZgD9Kd7ub2U5JZeM+QLavAjwDPtRX2HFwf01WtyOSM/b1aiAYcyPeSBNdDcSeNHQolVJNVBS0TFwB9ADQmHmImVcBfBPA83HrPA/g6+HH3wbwLCXKzcwQj+bD4ZZaVKeQa9+pVGJ/lr/koZIUOnrjyhSI3fXo3mooVSUbTg6MNFEgtpCcUU00Ok1UiEKSiQDQDGAk6vloeFnCdZjZD2AGQMLOcCJ6iYj6iah/YmJi241ZXgtgeGI+5Vx7otDNvr5BHcEsfcmH9AU8mF3eNCNJZJ/FQnj+SDM+8PjeDQPxnj/ShMf312y4QnOpsWmiQhQSWwbeI9EpbfyRNJV1QguZXwbwMgB0d3dv+4hcZrfi/L/9AFYSVHlMxt3lwCsXRnH9/mxM1dBMMa4uZACY+f7tR+J7J0N+/VQ7fv1U+4blxgxyXs2Hp1okfVcUlkxcAYwCaI163gJgLNk6RGQDUAsga0V47FYLqkpTj23GmXm2uoE8AzpaG8rR5qjIyvuL7NmsmqgQ+S4TAeBtAF1E1EFEJQBeAPBq3DqvAvhE+PHHAbzBOZRcvaemDF17qrJyI9gfCOL0kE+6f/JYr+pIWE1UiHyXdgAI9+n/NoAfArgB4L8y8ztE9O+I6GPh1b4GwEFEGoB/CWBDqqjZjFzwTE8Ecm1sFnPLfin/kMfcqrKhmqgQhSAj4wCY+TVmfoSZncz8ufCyP2TmV8OPl5n5nzCzysw9zDyUie1mkltVsLwWxIU7mZ0m0ug66HXKALB8laiaqBCFoCBHAu/Eic4GWC2U8b5ez4COx/fXwFFVmtH3FbvHmHRe7gOIQiMBIKy6zI7DLbWRInKZsLQawPk7U1L+oQC4VAVX781gZnHN7KYIkTESAKK4VQWXR6Yxu5yZL3n/nckNo05FfnJHVRMVolBIAIjSG/6Sn8lQeWiPpsNuJfR0bF2SQuS2I611KLdbpRtIFBQJAFGOtoW+5H0ZCgB9mg9H2+pRUZKJ8XbCTCU2C050NmS0i1AIs0kAiFJqs6KnowFvDWy/BEW8qYVVXBuT6R8LiTtcTXRsesnspgiRERIA4rhUBwYnFvBgJr25YE8P+cCMTaekFPmlN8sjxoXYbRIA4hg3bPvSvNT3ajqqSm1SP6aAPLavGo7Kkox1EQphNgkAcR7fV4OGypK0B/14NR0nOxtgt8qfuFBYLIReVYFHk2kiRWGQo1Mci4VwyumAN40v+ejUIm77FmX2rwLkcjowMbeCgYfzZjdFiLRJAEjArSoYn13B4MTCjn6/Twt1Ebi7JAAUGqOLUO4DiEIgASABd5pfco+mo7G6FF17qjLZLJEDWhsqcMBRIQFAFAQJAAm0NlSgtaF8R/cBmBl9gzpcTgeyOOulMFGvU8GZoUn4A6lPOiRELpIAkIRbVXBmyLftL/mt8Tno86tS/qGAuVUF8yt+XB6VaSJFfpMAkIRLVTC37MfVe9v7knsG9Mjvi8J0yukAkdwHEPlPAkASpzqNuWC39yX3ajo6lUo01ZVno1kiBzRUluDg/hqZH0DkPQkASTiqSrf9JV/1B3F2eFLO/ouAW1Vw8e4UFlf9ZjdFiB2TALAJd5eCC3emsbSa2jSRl0ensbgakPIPRcClKlgLMM4OT5rdFCF2TALAJlyqgtVAEG/fTu1L7hnQYSHgVKdcARS64+0NKLFa0CfdQCKPSQDYxPH2etitqU8T6dV0HGquRW2FPcstE2YrL7Hi2IE6eDSpCyTyV1oBgIj+hIhuEtEVIvouESWsfEZEt4noKhFdIqL+dLa5mypKbDjWVp9SDfj5FT8ujUxL/38RcasKbtyfhW9+xeymCLEj6V4B/BjAk8z8FIB3AfyrTdZ9HzMfYebuNLe5q9yqgnfGZjG5sLrpeueGffAHWer/F5H1yrFyFSDyU1oBgJl/xMxGGsQZAC3pNym39KoKmIHTW3zJPQM+lNosOHagfpdaJsx2qLkW1WU2GQ8g8lYm7wH8JoAfJHmNAfyIiM4T0UubvQkRvURE/UTUPzGR/sxc6TrcUouqUtuW3UB9gzqOtzegzG7dpZYJs9msFpzqdMg0kSJvbRkAiOgnRHQtwc/zUev8awB+AH+b5G1czHwMwHMAPk1E70m2PWZ+mZm7mbm7sbFxmx8n82xWC052OjY9y3s4t4ybD+ak/78IuVQFI5NLuOtbNLspQmzblrOVM/P7N3udiD4B4CMAnuUkBfSZeSz870Mi+i6AHgBvbr+55nCpDvzkxjhGJhfR2lCx4XWje0jy/4uPEfQ9mo5fc7SZ3BohtifdLKAPAfgDAB9j5oSnQERUSUTVxmMAHwRwLZ3t7jb3FtNEejUdteV2PNFUu5vNEjnA2ViJfTVl0g0k8lK69wC+BKAawI/DKZ5fBQAiaiKi18Lr7AXgIaLLAM4B+Admfj3N7e4qdU8V9lSXJsz5ZmZ4BnT0Oh2wWqT8c7EhIrhUBX2ajmBQpokU+WXLLqDNMLOaZPkYgA+HHw8BOJzOdsxmfMnffHcCwSDDEnWgv+1bxNjMMn7rfdL/X6xcqgOvXBjF9fuzeLJZrgLfHZ/DueFJ/LOTB8xuitiCjAROkUtV4FtYxa3xuZjlxs1hl1P6/4uVa4suwmLzpTc0/JvvXcPDuWWzmyK2IAEgRcYN3vhsIK+mo7muHB1KpRnNEjlgb00ZuvZUSVkIAMEgR74jffL3yHkSAFK0v7YczsbKmPLQgSCjb9AHlyrTPxY7l6rg3LAPK/7UKscWqlvjc/CFR83LfAm5TwLANoS+5JNY9YemiXxnbAYzS2uS/y/gUhUsrwVx8e602U0xlXH2f7StDn2ajiSZ4SJHSADYBpeqYHE1gEsjoS+5N3yJ2+uUAFDsTnQ2wGpJvXJsoTJmxPvlYy0Ym1nGsL5gdpPEJiQAbMPJTgcstH5p69V0PLavGo3VpSa3TJitpsyOwy21Rd3tET0jnjF2ptgDYq6TALANteV2HGoJXdourwVw7vaknP2LCJeq4MroDGaX18xuiimiZ8Q74KhAc1155CpZ5CYJANvkVh24NDKNn787gVV/EO4uSf8UIS5VQSDIODtUnNNEegZ0UHhGvNDYGQf6BnUEZIBczpIAsE0uVYE/yPiPPxmAzULo6ZAAIEKOttWh3G4t2m4Pr6bjqagZ8VyqgtllP67dmzG5ZSIZCQDbdKytHqU2C27cn8WR1jpUlaY1mFoUkFKbFcc7GooyABgz4vVGZcQZ3aNSJyl3SQDYpjK7FT0dDQAg6Z9iA7fqwMDDeYzPFtco2EQz4jVWl+KxfdVFGRDzhQSAHTAO/BIARLxIeeiB2IMeM+NX/+I0/suZO2Y0K+s8Az6U2Cx4Om5GPJeq4O3bU1heK54BcsEg45e/0odvvX3X7KZsSQLADvzaiTZ87hefRLdM/yjiPL6vBg2VJRu6PQYn5nF2eBLfuTBqUsuyy6vpON5ev2FGPJfqwKo/iP7bUya1bPfdeDCL83em8MqFe2Y3ZUsSAHagpsyOf3riQExVUCEAwGIhnHI60Kf5YkbBGumQhZgm+nBuGbfGE8+I19PhgM1CRXUfwKinZ4QCAAAXqElEQVSBdPHuFBZX/VusbS4JAEJkmFtV8GB2GYMT66NgPZoOm4UKMk3UmBHPnSAAVJXacLStrqjuAxj7ei3AODec2/taAoAQGeZyxpaH9geCODPow/NHmlFmtxTcwdAzoKOmzJZ0RjyXquDqvRlML67ucst236o/iHPDk/ilY80oseb+vpYAIESGtTkq0NpQHrkRfOXeDOZW/HjfY43o6XDk/EFhO5hD5Z97nUrSGfFcqgJm4MxQ4Y8Kvnh3CktrATz7+F4cO1CX8yOhJQAIkQVuVcHpIR/8gSD6wgf8XqcCl7Ow0kSNGfFcXckz4o601qGyxFoUdZK8mg4LheqGuVUF1+/Pwje/YnazkpIAIEQW9DoVzC37cW1sFh5NxxNNoewgV4EVSfOkMCOe3WrBiU5Hzp8NZ4JH0/FUSx1qy+1RM8Xl7ueWACBEFvSGD4g/uT6OC3emIweDg/trUF9hL5iDYZ+mo6m2bMsZ8VyqgmF9Afeml3apZbtvbnkNl0dnIrMHHmquRXWpLaenCk0rABDR/0lE94joUvjnw0nW+xAR3SIijYg+m842hcgHjqpSHNxfg6/33cZqIBgJABYLoVdV4C2AyVLWZ8RTtpwRL9mUqoXk7NAkAkGO7Gub1YKTTkdOd31l4grgz5j5SPjntfgXicgK4MsAngNwEMCLRHQwA9sVIqe5VAfmVvywWwnH29cHDbqcG9NE89F2ZsR7dG81lKqSgg4AHk1Hqc2CY23R+9qBkckl3PUtmtiy5HajC6gHgMbMQ8y8CuCbAJ7fhe0KYSrjwHisrR4VJetFA91qbJpovorMiKduXRE3VB5agTdugFw+6r89iWCCEtd9gzp6OhpiRkO7u3K7IF4mAsBvE9EVIvrPRJSoNkIzgJGo56PhZQkR0UtE1E9E/RMTExlonhDm6OloQG25HR84uDdmuZEm+tZAbh4UUuXVdDyytwp7qstSWt+lKtDnV3BrfC7LLcue/tuT+PhXT+O/XRmLWf5wdhnvjs9vmCDK2ViFvTWlG2pD5YotAwAR/YSIriX4eR7AVwA4ARwBcB/AnyZ6iwTLkp4CMPPLzNzNzN2NjY0pfgwhck9FiQ2eP3gfftPVseE1l1PBmXCaaD5aXgvg7duT2yqIuJ4Blb83wN98dyL8b+wB3TjDfyYuHZaI4HIq6BvUE141mG3LAMDM72fmJxP8fJ+Zx5k5wMxBAH+JUHdPvFEArVHPWwCMJVhPiIJTXWZPWDPKpa6nieajC3emsOIPJiz/kExzXTk6lMrIuIh85A2ndPYN6htqPdVV2HFwf82G33GpCqYW13DjQe7t63SzgPZHPf1FANcSrPY2gC4i6iCiEgAvAHg1ne0Kke+MNNF8vSnq0XRYLYQTndubEc+lOnBmyIe1PLzymVtew6WRaeyvLcP9mWUM6aGb+OujoR1Jgz2Qm/s63XsAf0xEV4noCoD3Afg9ACCiJiJ6DQCY2Q/gtwH8EMANAP+Vmd9Jc7tC5DVHVSke31+Ts33DW/Fq+o5mxHM5FSysBnB5ZDpLLcseI83zM+/vArB+QB/SF3B/Zjlpd9i+2jI4GyvhycGur7QCADP/OjMfYuanmPljzHw/vHyMmT8ctd5rzPwIMzuZ+XPpNlqIQuBWHTh/ZwpLq/k1WcrM4hqu3pvZ0YRIp5wOEOXnfQDvoI4yuwXPH2lGS/16rSejS2uz7jC3quDt4Ums+HNrX8tIYCFM4lIVrAaC6L+T2yWD450e8iHImx/wkqmrKMGh5tqc7A7ZSmjSm1CaZ3StJ4+mo7muHG0NFUl/16UqWFoL4OLd3LrykQAghEl6Ohpgt1JOjxRNxKvpKLdbcaS1bke/3+tUcOHuFBZWcnuylGhGmmf0dLBzy35cHp3B6UEf3FuMhj7R6YCFcu8+gAQAIUxSUWLD0bb6nDsobMWr6TjR2YAS284OH25VgT+Y+5OlRDPSPI2rHuMm/l/8fBCzy/5Nq6ECQG25HU+11OVcsJcAIISJ3KqCd8ZmMbWQH5OljE0vYUhf2FH3j6G7vR4lttyfLCVafJqncRP/R9fHAawHhM24VSXnpgSVACCEiVyqA8yhfvV84I2a22CnyuxWdB+oz7mz4WSSpXm6wyUwHttXDaWqdMv36VUdOTclqAQAIUz0VEsolTLRwfDH18fxV28NmdCq5LyaDkdlCR7bV53W+7hUBTcfzGFiLncnSzEkS/PsDT9P9WroWFt9zk0JKgFACBPZrRac7GxIODr2i28M4I9fv5UzaaLMDO+gD6eSDHjaDuOgmQ9XPsa+ccVd9ZzqdOCjh5vwK8dbE/3aBmV2K463N0gAEEKsc6kKbvsWMTK5XjJ4enEVV+/N5FSa6MDDeUzMrWyod7MTTzbXoqbMBm8eDITzaDpa6stxwBGb5llmt+KLLx7FI3tTvxpyq0pOTQkqAUAIk7kSlIc+PeiDUWomV/rKjYFP6fT/G6wWwqnwZCm5XB46EGScHvTB5dx60ptU5FpZCAkAQpisa08VGqtLY0bHejQdlSVWHGurQ1+OjJrtG9RxwFGB1k0GPG2HW1Vwb3oJdydzc7IUALh2byalNM9UHdxfg7ocmhJUAoAQJiMiuFUlpsJk36APJzsd+EeP7MG1sRnT00TXAkGcGdpe+eetGO+VK1c4iXgiWU/bK3qXjMUSKg+dK1OCSgAQIgf0Oh3Q51dxa3wOo1OLGNYX4FIVuLtyI030yug05lf8G26EpqNDqcT+2rKc6Q5JxKvpKad5pqpXdeTMlKASAITIAZGz4QE90uXjUpVImqjZB0mv5gNRqJhbphjTRPYN+nJyspTltQD670ylNegtkVyaElQCgBA5oKmuHJ2NlfBqOjyaDqWqFI/srYLdasGJDvNTBz2ajieaatBQWZLR93WrCqYX13D9fu5NltJ/ewqr/mDG+v8NbQ0VMdVEzSQBQIgc4XIqODs8ib5BHW7VEck6MdJER6fMuVm6uOrHxbtTGe3+MRh967l4H8Cj6bBZCD3tDRl9X2OayNM5MCWoBAAhcoRLVbC4GoA+vxoZZQoA7vAZqFnZQOeGJ7EW4IzeADbsqSnDI3urTL/CSaRvUMextnpUbnPSm1S4unJjSlAJAELkiFPhksEAYg62Rppots+SA0FOmJni1XSUWC04nuEzYYNLVfD27Uksr6U+4jlZW4NBzsj9BGMgXjaCHpA7U4JKABAiR9RWhEoGdzZWormuPLI8UZpopvkDQTzzR2/ga57hDa95NB+OHahDeYk1K9t2qwqW14K4cHcqpfWDQcb7v/BzfPENbcNrn/z62/j9v7ucdpuMgXguNXM3vaMpOTIlqAQAIXLIF37lML76z57esDw6TTQbLo/OYGxmGT+49iBmuW9+BTfuz2Y8EyZaT0cDrBZKuYvr1vgchvWFDW2dW17DmwM6fnx9PO1J572DoYF4h3c46U0qXE7zpwSVACBEDulsrEpYWyY6TTQbjK6ISyPTmIuqV983uJ6Smi3VZXYcaU19shSjrTfuz0KfX68mem44NGn7/IofV0bTm3rRq4UG4tmt2TtEurrMnxI0rU9HRN8iokvhn9tEdCnJereJ6Gp4vf50tilEMYpOE80GT3iax/h69V5NR3WZDYeaa7OyXYNLVXBldBozS1tPlmK0FVgPUMbyEpsFRIBnYOc3zO9NL0UG4mVTT7v5U4KmFQCY+VeZ+QgzHwHwCoDvbLL6+8LrdqezTSGKlZEmmm73RjwjzfOFnlaU2S0xByTvoI5TnQ7YsngmDIS6Q4IMnN1ixPOqP4hzw5P45aebUV1miymj7dV0nOhowJNNtZEpHHfCCLLZDgCVpTYcba03tdZTRvYqhRKWfwXANzLxfkKIjYw00Usj6XVvxDPSPH/hsT043t4QGaF617eIkcmlrB8IAeBoWz3K7dYtr3AujUxjcTWAZ7oa0et04K2B0I3xh3Prk7a7VAUX05h03hs1EC/bXKpiaq2nTIX1ZwCMM/NAktcZwI+I6DwRvbTZGxHRS0TUT0T9ExMTGWqeEPnPSBPN9H0AI82z+0AD3KqCd8fn8XB2OXIlsBsBoMRmwYnOhi27QzyaDgsBJzsdcEVVEzXOot2qApfqwFqAce729vvWjekfowfiZZPZtZ62DABE9BMiupbg5/mo1V7E5mf/LmY+BuA5AJ8movckW5GZX2bmbmbubmxsTPmDCFHoaivsONRcm/H7AB7Nh6cP1KO8xLper35Qh3dQx76aMjgbKzO6vWRcTgWDEwt4MJN8shSvpuNQSx1qy+1RtfV98Gh6ZNL24+0NoUnndxAob43PbRiIl01PtdShssRq2n2ALQMAM7+fmZ9M8PN9ACAiG4BfAvCtTd5jLPzvQwDfBdCTmeYLUVxcqoJLI6HKnJkQSfMMjzY26tW/NaCjT9PhUjMzEUoqtposZW55DZdGpiOTsXdGVRONnrTdmHTeO7j9s2qvlv2sp2ihKUEdCacE3Q2Z6AJ6P4CbzDya6EUiqiSiauMxgA8CuJaB7QpRdNyqAn+QcW44M10GRhaNMTLVqFf/91fuY2pxLWsDoRJ5bF81HJUlSQOAkeZpHJyJCL1OBT++Mb5h0naXqmxIE02FV9PRqcQOxMu2RFOC7pZMBIAXENf9Q0RNRPRa+OleAB4iugzgHIB/YObXM7BdIYrOsQP1KLVZ0kpzjJYozbNXdWDVH8o02q0zYSAUfDabJtKj6Si1WXCsrT6yzN0V1VZnbAAAYtNEt7IWCOLskA+9uxj0gMRTgu6WtAMAM/9zZv5q3LIxZv5w+PEQMx8O/zzBzJ9Ld5tCFKsyuzUmUyfa8loAr14e23DwDAYZ3790L3KgjJYozdMY9du1pwp7a8oy/Ak251YVPJxbweDE/IbX+jQfejoaUGZfL0lhHPSb62InbT/UXLshTdRwb3op4VXG5ZFpLKwGsjrqOZFH9lZBqYqdEnS3yEhgIfKMS1Vw88EcHs7F3iz95rm7+J1vXET/ndiaOm9pOn73m5fwvYv3YpYnS/Nsa6jAkdY6fPRwU3Y+wCaMtrwVdwP34dwybo3PbZiQfk9NGXqdDnz0cFPMvQqrhWLSRKP9yes38c//+tyGNFGPpoPCGUa7KVTryQGvpu/6xDgSAITIM0a//Om47g0jkyQ+TdQzMBHzevz68QGAiPC9T7vwO892Za7RKWptqEBbQ8WGs+HoNM94/9//fBKffe6xDcuj00QNzAyP5kuYJurVdBxqrkVdRWYnvUlFr6rAt5C9Wk/JSAAQIs880VSL2nJ7TDeGPzxpO7CxL9k4mMZXE93tNM9UuVQFZ+MmS/EaaZ5NNdt6n9DvrgeTd8fnIzeGo7uHFlb8uHh3elfveUTbKgMqWyQACJFnjO4NT1T3xuXRGcyv+NHZWImLd9fTRH3zK7h+fxadjZUx1USDQd71NM9UuVUFcyt+XLk3A2B9cFav0wGrJfW2diaYdN646ulsrIQnKjCcG56EP8i73v9vaK4rR6eSvVpPyUgAECIP9aoKxmaWcdsX6t7whvuv/+UHHolJEzWyYP7XDz4KYL176Pr92V1P80yVMfG8MZBrWF/A2Mzyhv7/rRhpot7B9b51r6ajQ6nELx9riUkTNQrJPX2gfrO3zCqXGqr1lOhmfbZIABAiDxlnqsYZrTc8afv7H98bkybaNxhK8/zgwb0xZ5hGN5FZXR6baagswRNNNZGCbkabd3J27u5yRCadN9I8XapjQ5qoV9NxvL0+JsNotxm1ni6nWcp6OyQACJGH2h0VaK4rh3dAx+KqHxfCk7YbaaLGQdOj6TgZTvOMPsP0aD5T0jxT5VYVXLgzjcVVPzyaviHNM1VGmqhH0yNpni6nEkkT9Q7omJhbwc0Hc6YHw2zVetqMBAAh8lCoe8OB00M+nB2KnbTdpSq4NT6H83emMDK5FDlzNs4w3749iXPDPtMPeJvpVUOTpZwdmsTpwdBZ+07uVeypKUPXntCk80aa56nwvYTe8KCzyNXQNruYMi1btZ42IwFAiDzl7lIws7SGv3hzMGbSdqNf/09+eDP8PHRgM84wv/jGAJbXgjkdAI6316PEasFfvDmI2WV/Wm11qQrODU/iZ7cmYtI8jTTRb5y7i5oyG57M8qQ3qch0raetSAAQIk8ZN0XPDE1GqnkC62miZ4YmY9I8jTPMM0OTsFoIJzobTGv7VipKbDh2oC6S2rrdG8DR3KqCFX8Ql0di0zyNx2eGJtHrVLaVYZQtma71tBUJAELkqcbqUjwanj84OpvHaiGcCo9m7Y3rOjHKHD/VUouaMvsutnb7jC6Zx/ZVo7G6dMfvc6KzIXJwj+7m6VQqsS98DyRXsqEyXetpKxIAhMhj0f3+McvD5Z3jM2eM52blu2+H8RnS7aqqLrPjcEstSmwWdLevp3kSUdK/n1k2q/WUDbZd2YoQIit+49QBlNkteKqlLmb5x55qwvDEAj74xL6Y5T0dDfhf3tOJF3radrOZO3K4pQ7/4r1O/Ep3a9rv9XsfeAR3fIsb0jz/p2c60NpQjg4ld0ZDf/TwflwamUEgyFnvlqJEZVdzRXd3N/f395vdDCGEyBtEdJ6Zu1NZV7qAhBCiSEkAEEKIIiUBQAghipQEACGEKFISAIQQokhJABBCiCIlAUAIIYqUBAAhhChSOT0QjIgmANzZ4a8rAHZ3fjXzFeNnBorzcxfjZwaK83Nv9zMfYObGVFbM6QCQDiLqT3U0XKEoxs8MFOfnLsbPDBTn587mZ5YuICGEKFISAIQQokgVcgB42ewGmKAYPzNQnJ+7GD8zUJyfO2ufuWDvAQghhNhcIV8BCCGE2ETBBQAi+hAR3SIijYg+a3Z7soWIWonoZ0R0g4jeIaLfDS9vIKIfE9FA+N/6rd4r3xCRlYguEtHfh593ENHZ8Gf+FhGVmN3GTCOiOiL6NhHdDO/zU4W+r4no98L/t68R0TeIqKwQ9zUR/WciekhE16KWJdy3FPLn4ePbFSI6ls62CyoAEJEVwJcBPAfgIIAXieigua3KGj+A32fmxwGcBPDp8Gf9LICfMnMXgJ+Gnxea3wVwI+r5HwH4s/BnngLwSVNalV3/CcDrzPwYgMMIff6C3ddE1AzgdwB0M/OTAKwAXkBh7uv/B8CH4pYl27fPAegK/7wE4CvpbLigAgCAHgAaMw8x8yqAbwJ43uQ2ZQUz32fmC+HHcwgdEJoR+rxfD6/2dQD/ozktzA4iagHwjwH8Vfg5AfgFAN8Or1KIn7kGwHsAfA0AmHmVmadR4PsaoSlry4nIBqACwH0U4L5m5jcBTMYtTrZvnwfwNxxyBkAdEe3f6bYLLQA0AxiJej4aXlbQiKgdwFEAZwHsZeb7QChIANhjXsuy4j8C+N8BBMPPHQCmmdkffl6I+7wTwASAvw53ff0VEVWigPc1M98D8HkAdxE68M8AOI/C39eGZPs2o8e4QgsAiWZQLug0JyKqAvAKgM8w86zZ7ckmIvoIgIfMfD56cYJVC22f2wAcA/AVZj4KYAEF1N2TSLjP+3kAHQCaAFQi1P0Rr9D29VYy+v+90ALAKIDWqOctAMZMakvWEZEdoYP/3zLzd8KLx41LwvC/D81qXxa4AHyMiG4j1L33CwhdEdSFuwmAwtznowBGmfls+Pm3EQoIhbyv3w9gmJknmHkNwHcA9KLw97Uh2b7N6DGu0ALA2wC6wpkCJQjdNHrV5DZlRbjv+2sAbjDzF6JeehXAJ8KPPwHg+7vdtmxh5n/FzC3M3I7Qvn2Dmf8pgJ8B+Hh4tYL6zADAzA8AjBDRo+FFzwK4jgLe1wh1/Zwkoorw/3XjMxf0vo6SbN++CuA3wtlAJwHMGF1FO8LMBfUD4MMA3gUwCOBfm92eLH5ON0KXflcAXAr/fBihPvGfAhgI/9tgdluz9PnfC+Dvw487AZwDoAH4OwClZrcvC5/3CID+8P7+HoD6Qt/XAP4vADcBXAPwXwCUFuK+BvANhO5zrCF0hv/JZPsWoS6gL4ePb1cRypLa8bZlJLAQQhSpQusCEkIIkSIJAEIIUaQkAAghRJGSACCEEEVKAoAQQhQpCQBCCFGkJAAIIUSRkgAghBBF6v8HHrPw9o6N4QEAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 通过内置的random模块以纯Python的方式实现1000步的随机漫步\n",
    "import random\n",
    "position = 0\n",
    "walk = [position]\n",
    "steps = 1000\n",
    "for i in range(steps):\n",
    "    step = 1 if random.randint(0, 1) else -1\n",
    "    position += step\n",
    "    walk.append(position)\n",
    "    \n",
    "plt.plot(walk[:100])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用np.random模块一次性随机产生1000个“掷硬币”结果（即两个数中任选一个），\n",
    "# 将其分别设置为1或－1，然后计算累计和：\n",
    "\n",
    "nsteps = 1000\n",
    "draws = np.random.randint(0, 2, size=nsteps)\n",
    "steps = np.where(draws > 0, 1, -1)\n",
    "walk = steps.cumsum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-9"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 有了这些数据之后，我们就可以沿着漫步路径做一些统计工作了，比如求取最大值和最小值：\n",
    "walk.min()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "60"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "walk.max()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "297"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 该布尔型数组第一个最大值的索引\n",
    "(np.abs(walk) >= 10).argmax()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  1,   2,   3, ...,  46,  47,  46],\n",
       "       [  1,   0,   1, ...,  40,  41,  42],\n",
       "       [  1,   2,   3, ..., -26, -27, -28],\n",
       "       ...,\n",
       "       [  1,   0,   1, ...,  64,  65,  66],\n",
       "       [  1,   2,   1, ...,   2,   1,   0],\n",
       "       [ -1,  -2,  -3, ...,  32,  33,  34]], dtype=int32)"
      ]
     },
     "execution_count": 110,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 一次模拟多个随机漫步\n",
    "\n",
    "nwalks = 5000\n",
    "nsteps = 1000\n",
    "draws = np.random.randint(0, 2, size=(nwalks, nsteps)) # 0 or 1\n",
    "steps = np.where(draws > 0, 1, -1)\n",
    "walks = steps.cumsum(1)\n",
    "walks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(122, -128)"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 现在，我们来计算所有随机漫步过程的最大值和最小值：\n",
    "walks.max(), walks.min()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True,  True, ...,  True, False,  True])"
      ]
     },
     "execution_count": 112,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hits30 = (np.abs(walks) >= 30).any(1)\n",
    "hits30"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3368"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hits30.sum() # Number that hit 30 or -30"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "509.99762470308787"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 然后我们利用这个布尔型数组选出那些穿越了30（绝对值）的随机漫步（行），\n",
    "# 并调用argmax在轴1上获取穿越时间：\n",
    "crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1)\n",
    "crossing_times.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
